package DAO;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.UniqueConstraint;

import org.hibernate.Transaction;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;

@Entity
@Table(name="departments", uniqueConstraints = {@UniqueConstraint(columnNames = { "dept_name" })})
public class Department {

	private String dept_no;
	private String dept_name;
	
	Set<DepartmentEmp> department_emp = new HashSet<DepartmentEmp>();
	Set<DepartmentManager> department_manager = new HashSet<DepartmentManager>();
	
	
	public Department(){}
	public Department(String dept_no, String dept_name) {
		super();
		this.dept_no = dept_no;
		this.dept_name = dept_name;
	}
	
	//*******************GETTERS SETTERS************************************
	@Id
	@Column(name="dept_no")
	public String getDept_no() {return dept_no;}
	public void setDept_no(String dept_no) {this.dept_no = dept_no;}
	
	
	public String getDept_name() {return dept_name;}
	public void setDept_name(String dept_name) {this.dept_name = dept_name;}
	
	@OneToMany(mappedBy="department", targetEntity=DepartmentEmp.class,
			cascade=CascadeType.ALL)
    @Fetch(value = FetchMode.SELECT) 
	public Set<DepartmentEmp> getDepartmentEmp() { return department_emp; }
	public void setDepartmentEmp(Set<DepartmentEmp> department_emp) { this.department_emp = department_emp; }
		    
	@OneToMany(mappedBy="department", targetEntity=DepartmentManager.class,
		    cascade=CascadeType.ALL)
    @Fetch(value = FetchMode.SELECT) 
	public Set<DepartmentManager> getDepartmentManager() { return department_manager; }
	public void setDepartmentManager(Set<DepartmentManager> department_manager) { this.department_manager = department_manager; }
	
	//**********************METHODS************************************
	public void print(){
		System.out.printf("%s: %s\n", dept_no, dept_name);
	}
	/**
	 * Prints all employees in department
	 */
	public void printDeptEmps(){
		for(DepartmentEmp e : department_emp){
			e.print();
		}
	}
	
	/**
	 * Prints all managers in department
	 */
	public void printDeptMans(){
		for(DepartmentManager e : department_manager){
			e.print();
		}
	}
	//*******************STATIC METHODS**************************************
	public static void add(Department e){
    	Session session = HibernateContext.getSession();
    	Transaction tx = session.beginTransaction();
        {
        	session.save(e);
        }
        tx.commit();
        session.close();
        System.out.println("Department Added");
	}
	public static void load(){
    	Session session = HibernateContext.getSession();
    	Transaction tx = session.beginTransaction();
    	{
    		session.save(new Department("d0001", "Software Development"));
    	}
    	tx.commit();
    	session.close();
    	System.out.println("Department Table has been loaded");
    }
	
	public static void list(){
		Session session = HibernateContext.getSession();
		Criteria criteria= session.createCriteria(Department.class);
		List<Department> departments = criteria.list();
		criteria.addOrder(Order.asc("dept_no"));
		System.out.println("All Departments: ");
		for(Department d : departments){
			d.print();
		}
		session.close();
	}
	/**
	 * Finds department by department number
	 * @param dept_no
	 * @return
	 */
	public static Department findByNum(String dept_no){
		Session session = HibernateContext.getSession();
		Query query = session.createQuery("From Department where dept_no = :id");
		query.setString("id", dept_no);
		
		Department d = (Department) query.uniqueResult();
		session.close();
		return d;
	}
	
	/**
	 * Finds department by department name
	 * @param dept_name
	 * @return
	 */
	public static Department findByName(String dept_name){
		Department prototype = new Department();
    	prototype.setDept_name(dept_name);
    	Example ex = Example.create(prototype);
    	
    	Session sess = HibernateContext.getSession();
    	Criteria criteria = sess.createCriteria(Department.class);
    	criteria.add(ex);
    	Department d = (Department) criteria.uniqueResult();
    	sess.close();
    	return d;
	}
}
